package com.rustamg.filedialogs;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.apples.hexviewer2.R;
import com.rustamg.filedialogs.utils.HexKeyboardUtils;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Objects;


/**
 * Created at 31/01/15 12:27
 *
 * @author rustamg
 */
public abstract class FileDialog extends DialogFragment implements FileListAdapter.OnFileSelectedListener {

    public static final String ROOT_DIRECTORY = "root_directory";
    public static final String START_DIRECTORY = "start_directory";
    public static final String EXTENSION = "extension";
    private static final String OUT_STATE_CURRENT_DIRECTORY = "out_state_current_dir";
    private static final String EXTERNAL_ROOT_PATH = Environment.getExternalStorageDirectory().getPath();
    protected File mCurrentDir;
    protected File mRootDir;
    protected FileFilter mFilesFilter;
    protected Toolbar mToolbar;
    protected ProgressBar mProgress;
    protected RecyclerView mRecyclerView;
    protected int mIconColor;
    private UpdateFilesTask mUpdateFilesTask;
    protected String mExtension;
    protected int type;
    private int sArg = -1, ofn = 1;

    @Override
    public void onAttach(@NonNull Context activity) {
        super.onAttach(activity);
        int[] iconColorAttr = new int[]{R.attr.file_dialog_toolbar_icons_color};
        int indexOfAttrIconColor = 0;
        TypedValue typedValue = new TypedValue();
        TypedArray a = activity.obtainStyledAttributes(typedValue.data, iconColorAttr);
        mIconColor = a.getColor(indexOfAttrIconColor, Color.WHITE);
        a.recycle();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(getLayoutResourceId(), container);
    }

//    @Override
//    public void onResume() {
//        super.onResume();
//        Objects.requireNonNull(getDialog()).setOnKeyListener((dialogInterface, keyCode, keyEvent) -> {
//            if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
//                if (mCurrentDir.getPath().equalsIgnoreCase(EXTERNAL_ROOT_PATH)) {
//                    dismiss();
//                } else {
//                    mCurrentDir = mCurrentDir.getParentFile();
//                    refresh();
//                    return true;
//                }
//            }
//            return false;
//        });
//    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mToolbar = view.findViewById(R.id.toolbar);
        mProgress = view.findViewById(R.id.progress);
        mRecyclerView = view.findViewById(R.id.rv_files);
        mToolbar.setNavigationOnClickListener(v -> {
            if (mCurrentDir.getPath().equalsIgnoreCase(EXTERNAL_ROOT_PATH)) {
                dismiss();
            } else {
                mCurrentDir = mCurrentDir.getParentFile();
                refresh();
            }
        });
        extractArguments(savedInstanceState);
        initList();
    }

    protected void extractArguments(Bundle savedInstanceState) {
        Bundle arguments = getArguments();
        mRootDir = arguments != null ? (File) arguments.getSerializable(ROOT_DIRECTORY) : null;
        if (savedInstanceState != null) {
            mCurrentDir = (File) savedInstanceState.getSerializable(OUT_STATE_CURRENT_DIRECTORY);
        } else {
            mCurrentDir = (File) (arguments != null ? arguments.getSerializable(START_DIRECTORY) : null);
        }
        if (mCurrentDir == null) {
            mCurrentDir = new File(EXTERNAL_ROOT_PATH);
        }
        if (mRootDir == null) {
            mRootDir = mCurrentDir;
        }
        if (arguments != null && arguments.containsKey(EXTENSION)) {
            mExtension = arguments.getString(EXTENSION);
            mFilesFilter = new ExtensionFilter(mExtension);
        }
        if (arguments != null) {
            sArg = arguments.getInt("sArg");
            ofn = arguments.getInt("oFn");
        }
    }

    private void initList() {
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    }

    @Override
    public void onStart() {
        super.onStart();
        refresh();
    }

    public void refresh() {
        if (mUpdateFilesTask == null || mUpdateFilesTask.getStatus() == AsyncTask.Status.FINISHED) {
            mUpdateFilesTask = new UpdateFilesTask(mCurrentDir);
            mUpdateFilesTask.onPreExecute();
            mUpdateFilesTask.start();
//            mUpdateFilesTask.execute(mCurrentDir);
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        mUpdateFilesTask.cancel(false);
    }

    @Override
    public void onFileSelected(File file) {
        if (file.isDirectory()) {
            mCurrentDir = file;
            refresh();
        }
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable(OUT_STATE_CURRENT_DIRECTORY, mCurrentDir);
    }

    private File fileTmp;

    protected void sendResult(File file) {
        fileTmp = file;
        Fragment targetFragment = getParentFragment();
        if (targetFragment instanceof OnFileSelectedListener) {
            ((OnFileSelectedListener) targetFragment).onFileSelected(this, file);
        } else {
            Activity activity = getActivity();
            if (activity instanceof OnFileSelectedListener) {
                ((OnFileSelectedListener) activity).onFileSelected(this, file);
            }
        }
        dismiss();
    }

    protected abstract int getLayoutResourceId();

    @SuppressLint("StaticFieldLeak")
    private class UpdateFilesTask extends Thread {

        private final File[] files;
        private File mDirectory;
        private boolean iCl;

        private UpdateFilesTask(File... files) {
            this.files = files;
        }

        protected void onPreExecute() {
            mProgress.setVisibility(View.VISIBLE);
        }

        @Override
        public void run() {
            super.run();
            File[] files1 = doInBackground(files);
            if (getActivity() != null)
                getActivity().runOnUiThread(() -> onPostExecute(files1));
        }

        protected File[] doInBackground(File... files) {
            mDirectory = files[0];
            File[] mFileArray;
            if (type == 2) {
                mFileArray = files[0].listFiles(file -> !file.isHidden()
                        && !file.getName().startsWith(".") && file.isDirectory());
            } else {
                if (mFilesFilter != null) {
                    mFileArray = files[0].listFiles(mFilesFilter);
                } else {
                    mFileArray = files[0].listFiles(file -> !file.isHidden()
                            && !file.getName().startsWith("."));
                }
            }
            return mFileArray;
        }


        protected void onPostExecute(File[] localFiles) {
            if (!isCancelled() && getActivity() != null) {
                Drawable navIcon;
                if (mDirectory.getPath().equalsIgnoreCase(EXTERNAL_ROOT_PATH)) {
                    String mRootPathDisplayName = "/";
                    mToolbar.setTitle(mRootPathDisplayName);
                    navIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_cross_hex, null);
                } else {
                    mToolbar.setTitle(mCurrentDir.getPath().replace(EXTERNAL_ROOT_PATH, ""));
                    navIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.abc_ic_ab_back_material, null);
                }
                if (localFiles != null)
                    Arrays.sort(localFiles, (f1, f2) -> {
                        if (f1.isDirectory() && !f2.isDirectory()) {
                            return -1;
                        } else if (!f1.isDirectory() && f2.isDirectory()) {
                            return 1;
                        } else {
                            return f1.getName().compareToIgnoreCase(f2.getName());
                        }
                    });
                Objects.requireNonNull(navIcon).setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
                mToolbar.setNavigationIcon(navIcon);
                mRecyclerView.setAdapter(new FileListAdapter(getActivity(), localFiles, FileDialog.this));
                mProgress.setVisibility(View.GONE);
            }
        }

        private boolean isCancelled() {
            return iCl;
        }

        public void cancel(boolean b) {
            iCl = b;
        }

        public AsyncTask.Status getStatus() {
            return AsyncTask.Status.FINISHED;
        }
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        if (getActivity() != null) {
            HexKeyboardUtils.hideKeyboard(getActivity());
        }
        if (fileTmp == null)
            sendResult(null);
        super.onDismiss(dialog);
    }

    public int getsArg() {
        return sArg;
    }

    public int getOFN() {
        return ofn;
    }

    public int getType() {
        return type;
    }

    public interface OnFileSelectedListener {
        void onFileSelected(FileDialog dialog, File file);
    }
}
